package com.poster.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.poster.constant.AppConfig;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;

@Component
public class JWTUtils {

    private final AppConfig appConfig;

    private final Algorithm algorithm;

    private final ZoneId zoneId;

    private final Map<String, Object> jwtHeader;

    JWTUtils(AppConfig appConfig){
        this.appConfig = appConfig;
        algorithm = buildAlgorithm(appConfig.getJwtAlgorithm(), appConfig.getJwtSecret());
        zoneId = ZoneId.of(appConfig.getZoneId());
        jwtHeader = Map.of("typ", "JWT", "alg", appConfig.getJwtAlgorithm());
    }

    /**
     * 生成jwt令牌
     * @param expireMillion 过期时间（毫秒）
     * @param claimsFiller 负载填充回调
     * @return jwt令牌
     */
    public String createJWT(Consumer<JWTCreator.Builder> claimsFiller, int expireMillion) {
        Date now = Date.from(ZonedDateTime.now(zoneId).toInstant());
        Date expireTime = new Date(now.getTime() + expireMillion);

        JWTCreator.Builder builder = JWT.create()
                .withHeader(jwtHeader)
                .withIssuedAt(now)
                .withNotBefore(now)
                .withExpiresAt(expireTime)
                .withJWTId(UUID.randomUUID().toString());

        claimsFiller.accept(builder);

        return builder.sign(algorithm);
    }


    /**
     * 解密jwt并检查是否是合法签名
     * @param jwt jwt字符串
     * @return 负载字典
     */
    public Map<String, Claim> verifyAndGetJWTClaims(String jwt) {
        return JWT.require(algorithm)
                .build()
                .verify(jwt)
                .getClaims();
    }


    /**
     * 生成加密算法
     * @param algorithm 算法
     * @param secret 密钥
     * @return 加密算法
     */
    private static Algorithm buildAlgorithm(String algorithm, String secret) {
        byte[] key = secret.getBytes(StandardCharsets.UTF_8);
        return switch (algorithm.toUpperCase()) {
            case "HS256" -> Algorithm.HMAC256(key);
            case "HS384" -> Algorithm.HMAC384(key);
            case "HS512" -> Algorithm.HMAC512(key);
            default -> throw new IllegalArgumentException("不支持的加密算法: " + algorithm);
        };
    }

}
